//
// Created by xwt
//

#ifndef AGENT_AGENT_TYPES_HPP
#define AGENT_AGENT_TYPES_HPP

#include <string>
#include <vector>
#include <nlohmann/json.hpp>

///////////////////////////////////////////////////////////////////////////
struct agent_coverage_map {
    std::string childNode{};
    std::string node{};
    std::string uri{};
};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_coverage_map> {
        static void to_json(json &j, const agent_coverage_map &d) {
            j = json{{"childNode", d.childNode},
                     {"node",      d.node},
                     {"uri",       d.uri}};
        }

        static void from_json(const json &j, agent_coverage_map &d) {
            if (j.contains("childNode") && j["childNode"].is_string()) {
                d.childNode = j["childNode"].get<std::string>();
            } else {
                d.childNode = "";
            }

            if (j.contains("node") && j["node"].is_string()) {
                d.node = j["node"].get<std::string>();
            } else {
                d.node = "";
            }

            if (j.contains("uri") && j["uri"].is_string()) {
                d.uri = j["uri"].get<std::string>();
            } else {
                d.uri = "";
            }
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct agent_branchinfo {
    int attribute{};
    int destLine{};
    int executedCount{};
    int startColumn{};
    int startLine{};
};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_branchinfo> {
        static void to_json(json &j, const agent_branchinfo &d) {
            j = json{{"attribute",     d.attribute},
                     {"destLine",      d.destLine},
                     {"executedCount", d.executedCount},
                     {"startColumn",   d.startColumn},
                     {"startLine",     d.startLine}};
        }

        static void from_json(const json &j, agent_branchinfo &d) {
            if (j.contains("attribute") && j["attribute"].is_number_integer())
                d.attribute = j["attribute"].get<int>();
            else
                d.attribute = 0;
            if (j.contains("destLine") && j["destLine"].is_number_integer())
                d.destLine = j["destLine"].get<int>();
            else
                d.destLine = 0;
            if (j.contains("executedCount") && j["executedCount"].is_number_integer())
                d.executedCount = j["executedCount"].get<int>();
            else
                d.executedCount = 0;
            if (j.contains("startColumn") && j["startColumn"].is_number_integer())
                d.startColumn = j["startColumn"].get<int>();
            else
                d.startColumn = 0;
            if (j.contains("startLine") && j["startLine"].is_number_integer())
                d.startLine = j["startLine"].get<int>();
            else
                d.startLine = 0;
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct agent_hitinfo {
    int hit{};
    int total{};
};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_hitinfo> {
        static void to_json(json &j, const agent_hitinfo &d) {
            j = json{{"hit",   d.hit},
                     {"total", d.total}};
        }

        static void from_json(const json &j, agent_hitinfo &d) {
            if (j.contains("hit") && j["hit"].is_number_integer()) {
                d.hit = j["hit"].get<int>();
            } else {
                d.hit = 0;
            }

            if (j.contains("total") && j["total"].is_number_integer()) {
                d.total = j["total"].get<int>();
            } else {
                d.total = 0;
            }
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct agent_eleinfo {
    int attribute{};
    int endColumn{};
    int endLine{};
    int executedCount{};
    std::string name{};
    int startColumn{};
    int startLine{};
};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_eleinfo> {
        static void to_json(json &j, const agent_eleinfo &d) {
            j = json{{"attribute",     d.attribute},
                     {"endColumn",     d.endColumn},
                     {"endLine",       d.endLine},
                     {"executedCount", d.executedCount},
                     {"name",          d.name},
                     {"startColumn",   d.startColumn},
                     {"startLine",     d.startLine}};
        }

        static void from_json(const json &j, agent_eleinfo &d) {
            if (j.contains("attribute") && j["attribute"].is_number_integer()) {
                d.attribute = j["attribute"].get<int>();
            } else {
                d.attribute = 0;
            }
            if (j.contains("endColumn") && j["endColumn"].is_number_integer()) {
                d.endColumn = j["endColumn"].get<int>();
            } else {
                d.endColumn = 0;
            }
            if (j.contains("endLine") && j["endLine"].is_number_integer()) {
                d.endLine = j["endLine"].get<int>();
            } else {
                d.endLine = 0;
            }
            if (j.contains("executedCount") && j["executedCount"].is_number_integer()) {
                d.executedCount = j["executedCount"].get<int>();
            } else {
                d.executedCount = 0;
            }
            if (j.contains("name") && j["name"].is_string()) {
                d.name = j["name"].get<std::string>();
            } else {
                d.name = "";
            }
            if (j.contains("startColumn") && j["startColumn"].is_number_integer()) {
                d.startColumn = j["startColumn"].get<int>();
            } else {
                d.startColumn = 0;
            }
            if (j.contains("startLine") && j["startLine"].is_number_integer()) {
                d.startLine = j["startLine"].get<int>();
            } else {
                d.startLine = 0;
            }
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct agent_linesinfo {
    std::vector<int> attributes{};
    std::vector<int> executedCounts{};
    int start{};
};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_linesinfo> {
        static void to_json(json &j, const agent_linesinfo &d) {

            j = {{"attributes",     d.attributes},
                 {"executedCounts", d.executedCounts},
                 {"start",          d.start}};
        }

        static void from_json(const json &j, agent_linesinfo &d) {
            if (j.contains("attributes") && j["attributes"].is_array()) {
                d.attributes = j["attributes"].get<std::vector<int>>();
            } else {
                d.attributes = {};
            }

            if (j.contains("executedCounts") && j["executedCounts"].is_array()) {
                d.executedCounts = j["executedCounts"].get<std::vector<int>>();
            } else {
                d.executedCounts = {};
            }
            if (j.contains("start") && j["start"].is_number()) {
                d.start = j["start"].get<int>();
            } else {
                d.start = 0;
            }
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct agent_coverage {
    std::vector<agent_branchinfo> branchInfoes{};
    agent_hitinfo branches{};
    std::vector<agent_eleinfo> classInfoes{};
    agent_hitinfo classes{};
    agent_hitinfo cxty{};
    agent_hitinfo edges{};
    std::string element{};
    std::vector<agent_eleinfo> functionInfoes{};
    agent_hitinfo functions{};
    int hash{};
    agent_hitinfo instructions{};
    std::string kind{};
    agent_hitinfo lines{};
    agent_linesinfo linesInfo{};
    std::string name{};
    bool empty(){
        return branchInfoes.empty()&&classInfoes.empty()&&functionInfoes.empty()&&kind.empty()&&name.empty()&&element.empty();
    }
};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_coverage> {
        static void to_json(json &j, const agent_coverage &d) {
            j = {{"branchInfoes",   d.branchInfoes},
                 {"branches",       d.branches},
                 {"classInfoes",    d.classInfoes},
                 {"classes",        d.classes},
                 {"cxty",           d.cxty},
                 {"edges",          d.edges},
                 {"element",        d.element},
                 {"functionInfoes", d.functionInfoes},
                 {"functions",      d.functions},
                 {"hash",           d.hash},
                 {"instructions",   d.instructions},
                 {"kind",           d.kind},
                 {"lines",          d.lines},
                 {"linesInfo",      d.linesInfo},
                 {"name",           d.name},
            };
        }

        static void from_json(const json &j, agent_coverage &d) {
            if (j.contains("branchInfoes") && j["branchInfoes"].is_array()) {
                d.branchInfoes = j["branchInfoes"].get<std::vector<agent_branchinfo>>();
            } else {
                d.branchInfoes = {};
            }

            if (j.contains("branches") && j["branches"].is_object()) {
                d.branches = j["branches"].get<agent_hitinfo>();
            } else {
                d.branches = {};
            }

            if (j.contains("classInfoes") && j["classInfoes"].is_array()) {
                d.classInfoes = j["classInfoes"].get<std::vector<agent_eleinfo>>();
            } else {
                d.classInfoes = {};
            }

            if (j.contains("classes") && j["classes"].is_object()) {
                d.classes = j["classes"].get<agent_hitinfo>();
            } else {
                d.classes = {};
            }

            if (j.contains("cxty") && j["cxty"].is_object()) {
                d.cxty = j["cxty"].get<agent_hitinfo>();
            } else {
                d.cxty = {};
            }

            if (j.contains("edges") && j["edges"].is_object()) {
                d.edges = j["edges"].get<agent_hitinfo>();
            } else {
                d.edges = {};
            }

            if (j.contains("element") && j["element"].is_string()) {
                d.element = j["element"].get<std::string>();
            } else {
                d.element = "";
            }

            if (j.contains("functionInfoes") && j["functionInfoes"].is_array()) {
                d.functionInfoes = j["functionInfoes"].get<std::vector<agent_eleinfo>>();
            } else {
                d.functionInfoes = {};
            }

            if (j.contains("functions") && j["functions"].is_object()) {
                d.functions = j["functions"].get<agent_hitinfo>();
            } else {
                d.functions = {};
            }

            if (j.contains("hash") && j["hash"].is_number()) {
                d.hash = j["hash"].get<int>();
            } else {
                d.hash = 0;
            }

            if (j.contains("instructions") && j["instructions"].is_object()) {
                d.instructions = j["instructions"].get<agent_hitinfo>();
            } else {
                d.instructions = {};
            }

            if (j.contains("kind") && j["kind"].is_string()) {
                d.kind = j["kind"].get<std::string>();
            } else {
                d.kind = "";
            }

            if (j.contains("lines") && j["lines"].is_object()) {
                d.lines = j["lines"].get<agent_hitinfo>();
            } else {
                d.lines = {};
            }

            if (j.contains("linesInfo") && j["linesInfo"].is_object()) {
                d.linesInfo = j["linesInfo"].get<agent_linesinfo>();
            } else {
                d.linesInfo = {};
            }
            if (j.contains("name") && j["name"].is_string()) {
                d.name = j["name"].get<std::string>();
            } else {
                d.name = "";
            }

        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct agent_request {

};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_request> {
        static void to_json(json &j, const agent_request &d) {
            j = json::object();
        }

        static void from_json(const json &j, agent_request &d) {
            d = {};
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct agent_response {

};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_response> {
        static void to_json(json &j, const agent_response &d) {
            j = json::object();
        }

        static void from_json(const json &j, agent_response &d) {
            d = {};
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct agent_data {
    std::string bitMap{};
    std::vector<agent_coverage_map> coverageMaps{};
    std::vector<agent_coverage> coverages{};
    std::string createTime{};
    bool done{};
    std::string doneTime{};
    bool dryrun{};
    std::vector<std::string> exceptions{};
    std::string executeTime{};
    std::string fuzzingId{};
    std::string id{};
    std::string projectId{};
    bool reproduce{};
    agent_request request{};
    agent_response response{};
    int source{};
};
namespace nlohmann {
    template<>
    struct adl_serializer<agent_data> {
        static void to_json(json &j, const agent_data &d) {
            j = json{
                    {"bitMap",       d.bitMap},
                    {"coverageMaps", d.coverageMaps},
                    {"coverages",    d.coverages},
                    {"createTime",   d.createTime},
                    {"done",         d.done},
                    {"doneTime",     d.doneTime},
                    {"dryrun",       d.dryrun},
                    {"exceptions",   d.exceptions},
                    {"executeTime",  d.executeTime},
                    {"fuzzingId",    d.fuzzingId},
                    {"id",           d.id},
                    {"projectId",    d.projectId},
                    {"reproduce",    d.reproduce},
                    {"request",      d.request},
                    {"response",     d.response},
                    {"source",       d.source}
            };
        }

        static void from_json(const json &j, agent_data &d) {

            if (j.contains("bitMap") && j["bitMap"].is_string()) {
                d.bitMap = j["bitMap"].get<std::string>();
            } else {
                d.bitMap = "";
            }
            if (j.contains("coverageMaps") && j["coverageMaps"].is_array()) {
                d.coverageMaps = j["coverageMaps"].get<std::vector<agent_coverage_map>>();
            } else {
                d.coverageMaps = {};
            }
            if (j.contains("coverages") && j["coverages"].is_array()) {
                d.coverages = j["coverages"].get<std::vector<agent_coverage>>();
            } else {
                d.coverages = {};
            }
            if (j.contains("createTime") && j["createTime"].is_string()) {
                d.createTime = j["createTime"].get<std::string>();
            } else {
                d.createTime = "";
            }
            if (j.contains("done") && j["done"].is_boolean()) {
                d.done = j["done"].get<bool>();
            } else {
                d.done = false;
            }
            if (j.contains("doneTime") && j["doneTime"].is_string()) {
                d.doneTime = j["doneTime"].get<std::string>();
            } else {
                d.doneTime = "";
            }
            if (j.contains("dryrun") && j["dryrun"].is_boolean()) {
                d.dryrun = j["dryrun"].get<bool>();
            } else {
                d.dryrun = false;
            }
            d.exceptions = j.value("exceptions", std::vector<std::string>());
            if (j.contains("exceptions") && j["exceptions"].is_array()) {
                d.exceptions = j["exceptions"].get<std::vector<std::string>>();
            } else {
                d.exceptions = {};
            }
            if (j.contains("executeTime") && j["executeTime"].is_string()) {
                d.executeTime = j["executeTime"].get<std::string>();
            } else {
                d.executeTime = "";
            }
            if (j.contains("fuzzingId") && j["fuzzingId"].is_string()) {
                d.fuzzingId = j["fuzzingId"].get<std::string>();
            } else {
                d.fuzzingId = "";
            }
            if (j.contains("id") && j["id"].is_string()) {
                d.id = j["id"].get<std::string>();
            } else {
                d.id = "";
            }
            if (j.contains("projectId") && j["projectId"].is_string())
                d.projectId = j["projectId"].get<std::string>();
            else {
                d.projectId = "";
            }
            if (j.contains("reproduce") && j["reproduce"].is_boolean()) {
                d.reproduce = j["reproduce"].get<bool>();
            } else {
                d.reproduce = false;
            }
            if (j.contains("request") && j["request"].is_object()) {
                d.request = j["request"].get<agent_request>();
            } else {
                d.request = {};
            }
            if (j.contains("response") && j["response"].is_object()) {
                d.response = j["response"].get<agent_response>();
            } else {
                d.response = {};
            }
            if (j.contains("source") && j["source"].is_number_integer()) {
                d.source = j["source"].get<int>();
            } else {
                d.source = 0;
            }
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct body_ {

};
namespace nlohmann {
    template<>
    struct adl_serializer<body_> {
        static void to_json(json &j, const body_ &d) {
            j = json::object();
        }

        static void from_json(const json &j, body_ &d) {
            d = {};
        }
    };
}
///////////////////////////////////////////////////////////////////////////

struct normal_payload {
    body_ body{};
    std::string status{};
};
namespace nlohmann {
    template<>
    struct adl_serializer<normal_payload> {
        static void to_json(json &j, const normal_payload &d) {
            j = {{"body",   d.body},
                 {"status", d.status}};
        }

        static void from_json(const json &j, normal_payload &d) {
            if (j.contains("body") && j["body"].is_object()) {
                d.body = j["body"].get<body_>();
            } else {
                d.body = {};
            }
            if (j.contains("status") && j["status"].is_string()) {
                d.status = j["status"].get<std::string>();
            } else {
                d.status = "";
            }
        }
    };
}
///////////////////////////////////////////////////////////////////////////
struct normal_payload_arr {
    std::vector<normal_payload> arr{};
};
namespace nlohmann {
    template<>
    struct adl_serializer<normal_payload_arr> {
        static void to_json(json &j, const normal_payload_arr &d) {
            j = d.arr;
        }

        static void from_json(const json &j, normal_payload_arr &d) {
            if (j.contains("arr") && j["arr"].is_array()) {
                d.arr = j["arr"].get<std::vector<normal_payload>>();
            } else {
                d.arr = {};
            }
        }
    };
}


#endif //AGENT_AGENT_TYPES_HPP
